mod reference;
mod SLICE;
mod STRUCT;
mod MatchFunc;
mod Match1Func;
mod Match2Func;

use crate::Match1Func::{Coin, UsState, value_in_cents};
use crate::reference::refer;
use crate::SLICE::slice_func;




fn main() {
    let x = five(5);

    println!("Hello, world!{}", x);

    loopf();

    go();

    refer();

    let c = Coin::Quarter(UsState::Alaska);
    println!("{}", value_in_cents(c));


}

fn five(x: i32) -> i32 {
    x + 5
}


fn loopf() {
    let a = [10, 20, 30, 40, 50];

    for element in a.iter() {
        println!("the value is {}", element);
    }
}

fn go() {
    for number in (1..4).rev() {
        println!("{}!", number);
    }

    println!("LIFTOFF!");


    // 所有权
    // 每个值都有一个变量，这个变量是该值的所有者    每个值同时只能有一个所有者    当所有者超出作用域时，该值将被删除

    // 创建String类型的变量
    // 以下变量声明之前，操作系统必须在运行时来请求内存，String::from 来实现，当用完String之后，需要使用某种方式将内存返回给操作系统
    let mut s = String::from("hello");

    // 这步，在拥有GC的语言中，GC会跟踪并清理不再使用的内存；没有GC，就需要我们去识别内存何时不再使用，并调用代码将它返回给操作系统。
    // - 如果忘了，那就浪费内存 - 如果提前做了，变量就会变成非法 - 如果做了两次，也时bug，必须一个分配对应一次释放。
    // 而Rust中，对于某个值来说，当拥有它的变量走出作用范围时，内存会立即自动的交还给操作系统。（会调用drop函数 ）
    // 
}

// 在语义上，将值传递给函数和把值赋给变量时类似的;  将值传递给函数将发生移动或者复制
// 作用域说明例子
fn scope() {
    let s = String::from("hello");

    take_ownership(s);

    let x = 5;

    make_copy(x);

    println!("x: {}", x);
}

fn take_ownership(some_string: String) {
    println!("{}", some_string)
}

fn make_copy(some_number: i32) {
    println!("{}", some_number)
}


// 返回值和作用域
// 函数在返回值的过程中同样也会发生所有权的转移
// 一个变量的所有权总是遵循同样的模式：
// 当一个值赋给其他变量就会发生移动；当一个包含heap数据的变量离开作用域时，它的值就会被drop函数清理，除非数据的所有权移动到另一个变量上了。
fn scope1() {
    let s1 = gives_ownership();

    let s2 = String::from("hello");

    let s3 = take_and_gives_back(s2);
}

fn gives_ownership() -> String {
    let some_string = String::from("hello");

    some_string
}

fn take_and_gives_back(a_string: String) -> String {
    a_string
}

fn scope2() {
    let s1 = String::from("hello");

    let (s2, len) = calculate_length(s1);

    println!("The length of '{}' is {},", s2, len);
}

fn calculate_length(s: String) -> (String, usize) {
    let length = s.len();
    (s, length)
}

